
package common.util;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Vector;

/**
 * 工具类
 * @author 张明
 */
@SuppressWarnings("unchecked")
public class ToolUtil {
	/**
	 * 日期格式化字符串 yyyy-MM-dd
	 */
	public static final String yyyy_MM_dd           = "yyyy-MM-dd";
	
	/**
	 * 日期格式化字符串 yyyy-MM-dd HH:mm:ss
	 */
	public static final String yyyy_MM_dd_HH_mm_ss = new StringBuffer(yyyy_MM_dd).append(" HH:mm:ss").toString();
	
	/**
	 * 是否为空
	 * @param value 判断的值
	 * @return 当且仅当满足下列条件时才返回true
	 * <p>1.当满足null==value</p>
	 * <p>2.当value是集合(Collection)时如果集合内没有元素即isEmpty返回为true时</p>
	 * <p>3.当value是键值对(Map)时如果键值对内没有映射即isEmpty返回为true时</p>
	 * <p>4.当value是字符串并且满足equalsIgnoreCase["",undefined,NaN,NULL]时</p>
	 */
	public static boolean isNullOrEmpty(Object value){
		return isNullOrEmpty(value, "", "undefined", "NaN", "NULL");	
	}
	
	/**
	 * 是否为空
	 * @param value      判断的值
	 * @param nullValues 如果value是字符串哪些值代表空值在此数组内的元素都会被认为是空
	 * @return 当且仅当满足下列条件时才返回true         
	 * <p>1.当满足null==value</p>
	 * <p>2.当value是集合(Collection)时如果集合内没有元素即isEmpty返回为true时</p>
	 * <p>3.当value是键值对(Map)时如果键值对内没有映射即isEmpty返回为true时</p>
	 * <p>4.当value是字符串并且满足equalsIgnoreCase[nullValues]时</p>
	 */
	public static boolean isNullOrEmpty(Object value, String... nullValues){
		if (null == value){
			return true;
		}
		if (value instanceof Collection){
			return Collection.class.cast(value).isEmpty();
		}
		if (value instanceof Map){
			return Map.class.cast(value).isEmpty();
		}
		if (value.getClass().isArray()){
			return 0 == Object[].class.cast(value).length;
		}
		if (null == nullValues || 0 == nullValues.length){
			return false;
		}
		
		if (value instanceof String){
			for (String nullValue : nullValues){
				if (value.toString().trim().equalsIgnoreCase(nullValue)){
					return true;
				}
			}
		}
		
		return false;
	}
	
	/**
	 * 将集合转换成数组
	 * @param <T> 泛型参数(显示所返回的数组的类型)
	 * @param items         集合
	 * @param componentType 集合内元素的Class 
	 * @return              对应的数组
	 */
	
	public static <T> T[] collectionToArray(Collection<T> items, Class<T> componentType){
		T[] array = (T[])Array.newInstance(componentType, items.size());
		
		int index = 0;
		for (T item : items){
			Array.set(array, index, item);
			index++;
		}
		
		return array;
	}
	
	/**
	 * 将集合转换成数组
	 * @param items          集合
	 * @param componentTypes 集合内元素的Class对数组
	 * @return               对应的数组
	 */
	@SuppressWarnings({ "rawtypes" })
	public static Object[] collectionToArray(Collection items, Class[] componentTypes){
		Object[] array = (Object[])Array.newInstance(Object.class, items.size());
		
		int index = 0;
		for (Object item : items){
			Array.set(array, index, item);
			index++;
		}
		
		return array;
	}

	/**
	 * 数组合并
	 * @param componentType 数组元素类型
	 * @param arrays        需要合并的数组
	 * @return              合并后的新数组
	 */
	public static <T> T[] arrayMerge(Class<T> componentType, T[]... arrays){
		List<T> tmpResult = new Vector<T>();
		for (T[] array : arrays){
			for (T item : array){
				tmpResult.add(item);
			}
		}
		
		return collectionToArray(tmpResult, componentType);
	}
	
	/**
	 * 判断指定指定集合中的对象是否存在对应的属性值
	 * @param <T> 泛型参数(集合内元素的类型)
	 * @param <R> 泛型参数(对象属性的类型)
	 * @param collection 需要判断的集合
	 * @param attrName   需要判断的字段名
	 * @param value      比较的值 
	 * @param attrType   字段类型
	 * @return 当且仅当满足下列条件时才返回true 
	 * <p>1.在集合内有至少一个元素的属性值equals[value]返回值为true</p>
	 * <p>1.当value满足isNullOrEmpty时至少在集合内有一个元素的属性也满足这个条件</p>         
	 */
	public static <T, R> boolean containsAttribute(Collection<T> collection, String attrName, R value, Class<R> attrType){
		if (isNullOrEmpty(collection)){
			return false;
		}
		for (T item : collection){
			R fieldValue = BeanUtil.getBeanField(item, attrName, attrType);
			if (isNullOrEmpty(fieldValue) && isNullOrEmpty(value)){
				return true;
			}
			if (fieldValue.equals(value)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 获取集合内属性值集合
	 * @param <T> 泛型参数(属性类型)
	 * @param <E> 泛型参数(集合内元素类型)
	 * @param collection 集合
	 * @param attrName   属性名
	 * @param attrType   属性类型
	 * @return           集合内每一个元素的attrName的属性值数组
	 */
	public static <T, E> T[] getAttributes(Collection<E> collection, String attrName, Class<T> attrType){
		T[] attrs = (T[])Array.newInstance(attrType, ToolUtil.isNullOrEmpty(collection) ? 0 : collection.size());
		
		int index = 0;
		for (E element : collection){
			attrs[index] = BeanUtil.getBeanField(element, attrName, attrType);
			index++;
		}
		return attrs;
	}

	/**
	 * 对集合内元素做类型转换
	 * @param <T> 泛型参数(需要转换的类型)
	 * @param collection 集合
	 * @param itemType   转换的类型
	 * @return           强制类型转换后的新集合
	 */
	@SuppressWarnings("rawtypes")
	public static <T> Collection<T> castCollection(Collection collection, Class<T> itemType){
		Collection<T> result = new ArrayList<T>();
		for (Object item : collection){
			result.add(itemType.cast(item));
		}
		return result;
	}
	
	/**
	 * 序列化数组(以字符串形式表现)
	 * @param array  数组
	 * @param split  分隔符
	 * @return       序列化后的数组
	 */
	public static Serializable serializArray(Object[] array, String split){
		StringBuffer result = new StringBuffer();
		for (int i = 0; i < array.length; i++){
			result.append(((isNullOrEmpty(array[i])) ? "" : array[i].toString()));
			if (i != array.length - 1){
				result.append(split);
			}
		}
		return result.toString();
	}
	
	/**
	 * 序列化Map(以字符串形式表现)
	 * @param map   键值对
	 * @param split1 分隔符
	 * @param split2 分隔符
	 * @return      序列化后的键值对
	 */
	@SuppressWarnings("rawtypes")
	public static Serializable serializMap(Map map, String split1, String split2){
		StringBuffer result = new StringBuffer();
		int i = 0;
		for (Object key : map.keySet()){
			result.append(key).append(split1).append(map.get(key));
			if (i < map.size()){
				result.append(split2);
			}
			i++;
		}
		return result.toString();
	}


	/**
	 * 序列化日期对象(以字符串形式表现)
	 * @param format 格式化字符串
	 * @param date   日期对象
	 * @return       序列化后的日期对象
	 */
	public static Serializable serializDate(String format, Date date){
		return new SimpleDateFormat(format).format(date);
	}

	/**
	 * 序列化异常对象(以字符串形式表现)
	 * @param t 异常对象
	 * @return  序列化后的异常对象
	 */
	public static Serializable serializThrowable(Throwable t) {
		return isNullOrEmpty(t) ? "" : JSONUtil.format(t);
    }
}